﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

using ExtensibleEventViewer.Console.DomainModel;
using ExtensibleEventViewer.Console.EventArguments;
using ExtensibleEventViewer.Console.Presenters;
using ExtensibleEventViewer.Console.Views;
using ExtensibleEventViewer.Core.Primitives;


namespace ExtensibleEventViewer.Console.Controls
{
	/// <summary>
	/// Displays list of available event logs
	/// </summary>
	public partial class EventLogListControl : UserControl, IEventLogListView
	{
		private readonly EventLogListPresenter _presenter;

		/// <summary>
		/// Occurs when track status for some EventLogEntity object is changed
		/// </summary>
		public event EventHandler<EventLogTrackStatusChangedEventArgs> EventLogTrackStatusChanged;

		/// <summary>
		/// Default constructor
		/// </summary>
		public EventLogListControl ()
		{
			InitializeComponent();

			_presenter = new EventLogListPresenter(this);

			if (DesignMode)
			{
				clbEventLogList.Items.AddRange(new[] { "EventLog #1", "EventLog #2" });
			}
		}

		/// <summary>
		/// Loads data into control using Provider
		/// </summary>
		internal void LoadData(EventLogConnector connector, IEnumerable<TrackedEventLog> trackedEventLogs)
		{
			Connector = connector;

			Action loadEventLogListAsync = () =>
			                               	{
			                               		_presenter.LoadData();

			                               		CheckTrackedEventLogRecords(trackedEventLogs);
			                               	};

			loadEventLogListAsync.BeginInvoke(LoadEventLogListCompleted, loadEventLogListAsync);
		}

		internal void ClearList()
		{
			ExecuteOperation(() => clbEventLogList.Items.Clear());
		}

		private void CheckTrackedEventLogRecords(IEnumerable<TrackedEventLog> itemsToCheck)
		{
			foreach (TrackedEventLog eventLog in itemsToCheck)
			{
				if (string.Equals(eventLog.ProviderID, Connector.ProviderID))
				{
					for (int i = 0; i < clbEventLogList.Items.Count; i++)
					{
						if (string.Equals(eventLog.ComputerName, ((EventLogEntity)clbEventLogList.Items[i]).ComputerName))
						{
							if (string.Equals(eventLog.EventLogName, ((EventLogEntity)clbEventLogList.Items[i]).Name))
							{
								ExecuteOperation(() => clbEventLogList.SetItemChecked(i, true));
							}
						}
					}
				}
			}
		}

		private void LoadEventLogListCompleted(IAsyncResult result)
		{
			Action loadEventLogListAsync = (Action) result.AsyncState;

			loadEventLogListAsync.EndInvoke(result);
		}

		private void PopulateEventLogList(List<EventLogEntity> eventLogEntities)
		{
			ExecuteOperation(() => clbEventLogList.Items.AddRange(eventLogEntities.ToArray()));
		}

		public EventLogConnector Connector
		{
			get; 
			private set;
		}

		public List<EventLogEntity> EventLogEntities
		{ 
			set
			{	
				ExecuteOperation(() => PopulateEventLogList(value));			
			}
		}


		private void ExecuteOperation(Action operation)
		{
			if (clbEventLogList.InvokeRequired)
			{
				Action updateOperation = () =>
				                         	{
				                         		clbEventLogList.BeginUpdate();
				                         		clbEventLogList.Invoke(operation);
				                         		clbEventLogList.EndUpdate();
				                         	};

				clbEventLogList.Invoke(updateOperation);
			}
			else
			{
				clbEventLogList.BeginUpdate();
				clbEventLogList.Invoke(operation);
				clbEventLogList.EndUpdate();
			}
		}

		private void clbEventLogList_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			if (EventLogTrackStatusChanged != null)
			{
				EventLogEntity eventLog = (EventLogEntity) clbEventLogList.Items[e.Index];

				TrackedEventLog trackedEventLog = new TrackedEventLog
				                                  	{
				                                  		ComputerName = eventLog.ComputerName,
				                                  		EventLogName = eventLog.Name,
				                                  		ProviderID = Connector.ProviderID
				                                  	};

				EventLogTrackStatusChangedEventArgs eventArgs = new EventLogTrackStatusChangedEventArgs
				                                                	{
				                                                		EventLog = trackedEventLog,
				                                                		IsTracked = e.NewValue == CheckState.Checked
				                                                	};

				EventLogTrackStatusChanged(sender, eventArgs);
			}
		}
	}
}